昨天講到了可空類型,今天可以來了解一下延遲初始化,因為還蠻常使用到的
我們使用Android Studio開了專案,拉好UI元件後,需要在Activity類別中宣告這個物件的存在,兩者才會有關連,我們也才可以透過程式碼來控制元件,比如說按鈕的點擊事件。
如果我們不延遲初始化變數的話,會在MainActivity.kt這樣宣告TextView:
class MainActivity : AppCompatActivity() {
//因為要一定要賦值給變數但是又還不能初始化,就會寫這樣
private var textView : TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//textView初始化
textView = findViewById(R.id.textView)
//之後每次這個變數呼叫方法或函數都需要安全呼叫「?」
val length = textView?.text?.length
}
}
由上可知這樣的確很麻煩一直要對其可空性做處理。
所以,我們還有其他選擇:
lateinit關鍵字可以用在頂層變數或區域變數。這是告訴kotlin我們之後就會初始化它了,不要催我現在就給值的意思,延續上例是這樣使用的:
class MainActivity : AppCompatActivity() {
//var 關鍵字前標明lateinit
private lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//初始化
textView = findViewById(R.id.textView)
//可以正常呼叫方法了,不需要一直處理可空性啦~
val textlength = textView.text.length
Log.d("mainActivity", "onCreate: $textlength")
}
}
雖然好用但也有其需要注意的點:
避免沒有初始化或重複初始化。
這應該是固定的語法if(::該變數名.isInitialized)
意思是:如果變數已經初始化的話...
為了偷懶方便,我以上面textView舉例,一般不需要這樣寫:
if(!::textView.isInitialized) textView = findViewById(R.id.textView)
第二種避免使用可空類型的方式:lazy properties, lazy()是一個接受 lambda 並返回實例的函數,第一次呼叫該屬性的getter時,會執行lambda,傳遞給lazy()函數並記住結果。後續在呼叫getter時,就只會返回記住的結果。
看官方網站給的例子:
val lazyValue: String by lazy {
println("computed!")
"Hello" //呼叫getter時的返回值
}
fun main() {
println(lazyValue)
println(lazyValue)
//結果:
//computed! (初始化1次)
// Hello
// Hello (第2次就只返回記住的值,並不會再次執行初始化)
}
需要注意 :
參考
kotlin文檔 Lateinit top-level properties and local variables
kotlin文檔 lazy-properties
Khan Academy - lateinit
Kotlin使用心得(十一):lateinit vs lazy